package br.com.pentagrama.service;

import java.util.HashSet;

import java.util.Set;

import br.com.pentagrama.dto.InfoServico;
import br.com.pentagrama.dto.NomeParametro;
import br.com.pentagrama.dto.Parametros;
import br.com.pentagrama.exception.ParseConfException;
import br.com.pentagrama.util.ParseUtil;
import br.com.pentagrama.util.Sistema;

public class TestadorAmbiente implements ITestadorAmbiente {

	private static TestadorAmbiente instance;
	
	private IPing pingService;
	
	private IClienteConexao cliente;
	
	private ILog log;
	
	private Parametros parametros;
	
	public static TestadorAmbiente getInstance() {
		if(instance == null) {
			instance = new TestadorAmbiente();
		}
		return instance;
	}
	
	private TestadorAmbiente() {
		this.pingService = Sistema.getPing();
		this.parametros = Sistema.getParametros();
		this.cliente = Sistema.getClienteConexao();
		this.log = Sistema.getLog();
	}

	public long getLatenciaPing(String url) throws ParseConfException {
		int vezes = 0;
		String vezesTeste = parametros.get(NomeParametro.VEZES_TESTE_PING);
		String urlTeste = url + parametros.get(NomeParametro.PACOTE_PEQUENO);
		vezes = verificarParametros(vezesTeste, urlTeste);
		return pingService.doPing(urlTeste, vezes).getMedia();
	}

	private int verificarParametros(String vezesTeste, String urlTeste)
			throws ParseConfException {
		int vezes = -1;
		try {
			vezes = Integer.parseInt(vezesTeste);
		} catch (NumberFormatException n) {
			String mensagem = "Par\u00E2metro possui valor inv\u00E1lido: " + NomeParametro.VEZES_TESTE_PING;
			log.alerta(mensagem);
			throw new ParseConfException(mensagem + " -> " + vezesTeste); 
		}
		
		if(urlTeste == null) {
			String mensagem = "Par\u00E2metro possui valor inv\u00E1lido: " + NomeParametro.PACOTE_PEQUENO;
			log.alerta(mensagem);
			throw new ParseConfException(mensagem);
		}
			
		return vezes;
	}
	
	
	public void testarServico(InfoServico infoServico) {
		
		boolean conexaoIP = true;
		boolean conexaoUDP = true;
		boolean conexaoTCP = true;
		
		conexaoIP = verificarAlcanceIP(infoServico, conexaoIP);
		
		if(conexaoIP) {
			conexaoUDP = verificarAlcanceTCP(infoServico, conexaoUDP);
			
			conexaoTCP = verificarAlcanceUDP(infoServico, conexaoTCP);
		} else {
			conexaoUDP = false;
			conexaoTCP = false;
		}
		
		infoServico.setTcpStatus(conexaoTCP);
		infoServico.setUdpStatus(conexaoUDP);
		infoServico.setIpStatus(conexaoIP);
		
	}

	private boolean verificarAlcanceUDP(InfoServico infoServico,
			boolean conexaoTCP) {
		for (String tcp : infoServico.getTcpAcesso()) {
			if(!cliente.conectarTCP(tcp)) {
				conexaoTCP = false;
			}			
		}
		return conexaoTCP;
	}

	private boolean verificarAlcanceTCP(InfoServico infoServico,
			boolean conexaoUDP) {
		for (String udp : infoServico.getUdpAcesso()) {
			if(!cliente.conectarUDP(udp)) {
				conexaoUDP = false;
			}
		}
		return conexaoUDP;
	}

	private boolean verificarAlcanceIP(InfoServico infoServico,
			boolean conexaoIP) {
		Set<String> ips = new HashSet<String>();
		for (String udp : infoServico.getUdpAcesso()) {
			ips.add(ParseUtil.getIP(udp));
		}
		
		for (String tcp : infoServico.getTcpAcesso()) {
			ips.add(ParseUtil.getIP(tcp));
		}
		
		for (String destino : ips) {
			if(!pingService.isReachable(destino)) {
				conexaoIP = false;
			}
		}
		return conexaoIP;
	}

	public InfoServico getGravacao() {
		InfoServico infoServico = parametros.getGravacao();
		testarServico(infoServico);
		return infoServico;
	}

	public InfoServico getWebCasting() {
		InfoServico infoServico = parametros.getWebCasting();
		testarServico(infoServico);
		return infoServico;
	}

	public InfoServico getVideoSalasOutras() {
		InfoServico infoServico = parametros.getVideoSalasOutras();
		testarServico(infoServico);
		return infoServico;
	}

	public InfoServico getVideoSalasVydio() {
		InfoServico infoServico = parametros.getVideoSalasVydio();
		testarServico(infoServico);
		return infoServico;
	}

	public InfoServico getVideoDesktopMovel() {
		InfoServico infoServico = parametros.getVideoDesktopMovel();
		testarServico(infoServico);
		return infoServico;
	}
}
